<?php


namespace PKFrame\Driver;
defined('PATH_PK') or die();


use PKFrame\DataHandler\Arrays;

class MySQLi
{
    private $_config, $_index;
    private static $conn;
    private $conn_now;
    public $version = 0;

    public function __construct($config, $index)
    {
        $this->_config = $config;
        $this->_index = $index;
    }

    private function _notice(\Exception $exception)
    {
        out()->noticeByJson($exception->getMessage());
    }

    public function Conn(bool $is_connectDB = true)
    {
        $name_db = $is_connectDB ? $this->_config['name'] : null;
        try {
            if (!is_array(self::$conn) || !array_key_exists($this->_index, self::$conn)
                || empty(self::$conn[$this->_index])) {
                self::$conn[$this->_index] = new \mysqli(
                    $this->_config['host'],
                    $this->_config['user'],
                    $this->_config['pass'],
                    $name_db, $this->_config['port']);
                $this->version = mysqli_get_server_version(self::$conn[$this->_index]);
                if ($this->version >= 50530) {
                    mysqli_set_charset(self::$conn[$this->_index], 'utf8mb4');
                } else {
                    mysqli_set_charset(self::$conn[$this->_index], 'utf8');
                }
                if (self::$conn[$this->_index]->connect_errno) {
                    throw new \Exception("Connect failed: " . self::$conn[$this->_index]->connect_error);
                }
                $this->conn_now = self::$conn[$this->_index];
            } else if (array_key_exists($this->_index, self::$conn) && !mysqli_ping(self::$conn[$this->_index])) {
                unset(self::$conn[$this->_index]);
                $this->Conn($is_connectDB);
            } else {
                $this->conn_now = self::$conn[$this->_index];
            }
        } catch (\Exception $e) {
            logger()->ERROR($e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());
            out()->noticeByJson(language('DataBase_Connect_Error'));
        }
    }

    private function _errorLog($sqlStr)
    {
        try {
            if ($error_no = mysqli_errno($this->conn_now)) {
                $error = mysqli_error($this->conn_now);
                logger()->LOGS($error, ['sql' => $sqlStr, 'ErrorCode' => $error_no]);
                throw new \Exception($error);
            }
        } catch (\Exception $exception) {
            $this->_notice($exception);
        }
    }

    public function sqlQuery($sqlStr, int $index = 0)
    {
        !empty($sqlStr) ?: out()->noticeByJson('do sql is empty');
        !$this->_index = $index;
        $this->Conn();
        if (!mysqli_multi_query($this->conn_now, $sqlStr)) {
            $this->_errorLog($sqlStr);
        }
    }

    public function fetchAssoc($sqlStr, $toList = false, int $index = 0)
    {
        !empty($sqlStr) ?: out()->noticeByJson('do sql is empty');
        $this->_index = $index;
        $this->Conn();
        $result = [];
        if (!$query = mysqli_query($this->conn_now, $sqlStr)) {
            $this->_errorLog($sqlStr);
        }
        if ($toList) {
            while ($row = mysqli_fetch_assoc($query)) {
                $result[] = $row;
            }
        } else {
            $result = mysqli_fetch_assoc($query);
        }
        return $result;
    }

    public function insert($sql)
    {
        !empty($sql) ?: out()->noticeByJson('do sql is empty');
        if (Arrays::Is($sql)) {
            $sqlStr = implode(';', $sql);
            $this->sqlQuery($sqlStr);
        }
    }

    public function insertId($sqlStr, int $index = 0)
    {
        !empty($sqlStr) ?: out()->noticeByJson('do sql is empty');
        $this->_index = $index;
        $this->Conn();
        if (!mysqli_query($this->conn_now, $sqlStr)) {
            $this->_errorLog($sqlStr);
        }
        return mysqli_insert_id($this->conn_now);
    }

    public function __destruct()
    {
        if (Arrays::Is(self::$conn)) {
            foreach (self::$conn as $index => $item) {
                if (!empty(self::$conn[$index])) {
                    self::$conn[$index]->close();
                    unset(self::$conn[$index]);
                }
            }
        }
    }
}